// 只声明了一个存储 double 类型数据的环形缓冲区实例
// 使用 struct 定义能增加可读性, 这样就有点在 C 里做面向对象编程的意思了
// 但 struct 的缓冲区大小是写死的, 无法像 class 一样用构造函数确定大小, 动态分配
// 在嵌入式 C 代码里, 有些变量需要在全生命周期内, 全局可见, 大小又不变, 作为全局变量定义在堆区挺好的

// 数组是封装的指针. 建议可以使用数组的就不要用指针
// 严格区分指针命名 _p, _ptr 和数组下标命名 _index, _idx

// 嵌入式里尽量不要 malloc (C style) 或 new (C++)
// 动态变量看起来很酷, 在桌面端 8G 起步的内存随便造; 但无论在什么平台, 内存碎片, 泄露, 可够受的
// 除非你以后铁定心, 靠电子工程/嵌入式吃饭, 否则对指针, 动态内存管理敬而远之吧

/* Ring Buffer Begin */
const uint8_t rngBuf_size = 32;			// 环形缓冲区尺寸			必须声明常数大小的数组
uint8_t rngBuf_idx = 0;					// 缓冲区最新数据的数组下标
double rngBuf[rngBuf_size];				// 缓冲区占据实际体积
void rngBuf_push(double);				// 缓冲区服务函数: 输入
double rngBuf_get(uint8_t);				// 缓冲区服务函数: 输出第x个. 输入 0, 返回最新的数据, 1 返回次新的数据; 超过 size 的取模
/* Ring Buffer End */


void rngBuf_push(double latest_data)
{
	rngBuf_idx++;
	if (rngBuf_idx >= rngBuf_size) rngBuf_idx = 0; // 缓冲区从下往上, 写到顶了, 回到头部继续写, 覆盖掉最陈旧的数据.

	rngBuf[rngBuf_idx] = latest_data;
}

double rngBuf_get(uint8_t prev_count)
{
	// uint, 作为正数处理. 如果访问 0 号则弹出最新, 1 弹出次新
	// ; 如果缓冲长32个, 访问第32个, 则相当于访问 0 号. while 就是负数取余, 但不同平台行为不同, 故使用了这种写法.
	int8_t idx = (rngBuf_idx - prev_count);
	while (idx < 0) idx += rngBuf_size; 
	return rngBuf[idx];
}
